package com.qingzhuge.web.filter;

import com.qingzhuge.common.utils.WebUtil;
import com.qingzhuge.common.xss.SQLFilter;
import com.qingzhuge.autoconfigure.QingTingProperties;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Component;

import javax.servlet.*;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.Enumeration;
import java.util.List;

/**
 * @author : zero.xiao
 * @description : 非法字符过滤器（防SQL注入，防XSS漏洞）
 * @modified :
 */
@Slf4j
@Component
public class XssFilter implements Filter {
    private final QingTingProperties qingTingProperties;

    /**
     * 排除部分URL不做过滤
     */
    private List<String> excludeUrls;

    public XssFilter(QingTingProperties qingTingProperties) {
        this.qingTingProperties = qingTingProperties;
    }

    @Override
    public void init(FilterConfig filterconfig1) {
        excludeUrls = qingTingProperties.getFilter().getCsrfWhiteUrls();
    }

    @Override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
            throws IOException, ServletException {
        HttpServletRequest req = (HttpServletRequest) request;
        HttpServletResponse rep = (HttpServletResponse) response;
        String pathInfo = req.getPathInfo() == null ? "" : req.getPathInfo();
        String url = req.getServletPath() + pathInfo;
        String uri = req.getRequestURI();
        // 排除部分URL不做过滤。
        if (WebUtil.isWhiteRequest(uri, excludeUrls.size(), excludeUrls)) {
            chain.doFilter(req, rep);
            return;
        }
        // 获取请求所有参数，校验防止SQL注入，防止XSS漏洞

        log.debug("校验URL：" + url);
        Enumeration<?> params = req.getParameterNames();
        String paramN;
        while (params.hasMoreElements()) {
            paramN = (String) params.nextElement();
            if ("sign".equals(paramN)) {
                log.debug("跳过签名字段");
                continue;
            }
            String paramVale = req.getParameter(paramN);
            if (!paramN.toLowerCase().contains("password")) {
                log.debug(paramN + "==" + paramVale);
            }
            // 校验是否存在SQL注入信息
            if (checkSQLInject(paramVale, url)) {
                errorResponse(rep, paramN);
                return;
            }
        }

        XssHttpServletRequestWrapper xssRequest = new XssHttpServletRequestWrapper(req);
        chain.doFilter(xssRequest, rep);
    }

    private void errorResponse(HttpServletResponse response, String paramNm) {
        String warning = "输入项中不能包含非法字符。";
        WebUtil.writer(response,"{\"code\":\"309\",\"message\":\"" + warning + "\", \"fieldName\": \"" + paramNm + "\"}");
    }

    @Override
    public void destroy() {
    }

    /**
     *
     * 检查是否存在非法字符，防止SQL注入
     *
     * @param str
     *            被检查的字符串
     * @return ture-字符串中存在非法字符，false-不存在非法字符
     */
    private boolean checkSQLInject(String str, String url) {
        if (StringUtils.isEmpty(str)) {
            // 如果传入空串则认为不存在非法字符
            return false;
        }

        if (SQLFilter.checkSQLInject(str)) {
            log.debug("xss防攻击拦截url:" + url + "，原因：特殊字符，传入str=" + str);
            return true;
        }
        return false;
    }
}
